package com.example.bankmanage.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.bankmanage.convention.exception.ClientException;
import com.example.bankmanage.dto.rep.AddBillReqDTO;
import com.example.bankmanage.dto.rep.BillExportReqDTO;
import com.example.bankmanage.dto.rep.GetBillListReqDTO;
import com.example.bankmanage.dto.rep.UpdateBillReqDTO;
import com.example.bankmanage.dto.resq.BillExcelRespDTO;
import com.example.bankmanage.entity.PageBean;
import com.example.bankmanage.entity.bills;
import com.example.bankmanage.mapper.BillMapper;
import com.example.bankmanage.service.BillService;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jodd.bean.BeanUtilBean;
import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.implementation.bytecode.StackSize;
import org.apache.poi.ss.usermodel.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.OutputStream;
import java.util.List;
import java.util.stream.Collectors;

import static com.alibaba.excel.write.metadata.style.WriteCellStyle.build;
import static com.example.bankmanage.convention.errorcode.UserErrorCodeEnum.*;

@Service
@Slf4j
public class BillServiceimpl extends ServiceImpl<BillMapper, bills> implements BillService {
    @Autowired
    private BillMapper billMapper;
    @Override
    public PageBean<bills> getBillList(GetBillListReqDTO requestParam) {
        // 构建分页参数
        Page<bills> page = new Page<>(requestParam.getPage(), requestParam.getSize());

        // 构建查询条件
        LambdaQueryWrapper<bills> queryWrapper = new LambdaQueryWrapper<>();

        // 添加查询条件
        queryWrapper.eq(requestParam.getBillType() != null, bills::getBillType, requestParam.getBillType())
                .eq(requestParam.getPaymentStatus() != null, bills::getPaymentStatus, requestParam.getPaymentStatus())
                .eq(requestParam.getAccountId() != null, bills::getAccountId, requestParam.getAccountId())
                .ge(requestParam.getStartDate() != null, bills::getDueDate, requestParam.getStartDate())
                .le(requestParam.getEndDate() != null, bills::getDueDate, requestParam.getEndDate());

        // 添加排序条件
        if (StringUtils.isNotBlank(requestParam.getSortField()) && StringUtils.isNotBlank(requestParam.getSortOrder())) {
            queryWrapper.orderBy(true, "asc".equalsIgnoreCase(requestParam.getSortOrder()),
                    getSortField(requestParam.getSortField()));
        } else {
            // 默认按账单ID降序
            queryWrapper.orderByDesc(bills::getBillId);
        }
        page = baseMapper.selectPage(page, queryWrapper);
//        System.out.println(page.getPages());
//        System.out.println(page.getTotal());
        //这里的mybatis-plus里的count指令没有执行,要调
        PageBean<bills> pageBean = new PageBean<>();
        pageBean.setContent(page.getRecords());
        pageBean.setTotalElements(page.getTotal());
        // 执行查询
        return pageBean;
    }

    @Override
    public void addBill(AddBillReqDTO requestParam) {
        int inserted= baseMapper.insert(BeanUtil.toBean(requestParam, bills.class));
        if(inserted  < 1){
            throw new ClientException(BILL_SAVE_ERROR);
        }
    }

    @Override
    public void updateBill(Integer billId, UpdateBillReqDTO requestParam) {
        LambdaUpdateWrapper<bills> UpdateWrapper = Wrappers.lambdaUpdate(bills.class)
                .eq(bills::getBillId, billId);
        int update = baseMapper.update(BeanUtil.toBean(requestParam, bills.class), UpdateWrapper);
        if(update < 1){
            throw new ClientException(BILL_UPDATE_ERROR);
        }
    }

    @Override
    public void deleteBill(Integer billId) {
        LambdaUpdateWrapper<bills> UpdateWrapper = Wrappers.lambdaUpdate(bills.class)
                .eq(bills::getBillId, billId);
        int delete = baseMapper.delete(UpdateWrapper);
        if(delete < 1){
            throw new ClientException(BILL_DELETE_ERROR);
        }
    }
    @Override
    public void exportBill(BillExportReqDTO exportDTO, OutputStream outputStream) {
        // 1. 查询数据
        List<bills> bills = billMapper.selectBillsForExport(exportDTO);
        System.out.println(bills);
        if (CollectionUtils.isEmpty(bills)) {
            throw new RuntimeException("没有可导出的数据");
        }

        // 2. 导出Excel
        try (ExcelWriter excelWriter = EasyExcel.write(outputStream)
                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) // 自动列宽
                .build()) {

            WriteSheet writeSheet = EasyExcel.writerSheet("账单数据")
                    .head(BillExcelRespDTO.class)
                    .registerWriteHandler(new HorizontalCellStyleStrategy(
                            getHeaderStyle(),
                            getContentStyle())) // 自定义样式
                    .build();

            // 3. 数据转换并写入Excel
            excelWriter.write(convertToExcelVO(bills), writeSheet);
            System.out.println(excelWriter);
            excelWriter.finish(); // 确保写入完成
        }
    }

    private List<BillExcelRespDTO> convertToExcelVO(List<bills> bills) {
        return bills.stream().map(bill -> {
            BillExcelRespDTO vo = new BillExcelRespDTO();
            // 这里进行属性拷贝
            BeanUtils.copyProperties(bill, vo);
            System.out.println(vo);
            // 特殊字段处理
//            vo.setPaymentStatus(String.valueOf(bill.getPaymentStatus()));
            return vo;
        }).collect(Collectors.toList());
    }
    // 内容单元格样式
    private WriteCellStyle getContentStyle() {
        WriteCellStyle style = new WriteCellStyle();

        // 1. 对齐方式
        style.setHorizontalAlignment(HorizontalAlignment.CENTER); // 水平居中
        style.setVerticalAlignment(VerticalAlignment.CENTER);   // 垂直居中

        // 2. 边框设置
        style.setBorderLeft(BorderStyle.THIN);          // 左边框
        style.setBorderRight(BorderStyle.THIN);         // 右边框
        style.setBorderTop(BorderStyle.THIN);           // 上边框
        style.setBorderBottom(BorderStyle.THIN);        // 下边框
        style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); // 边框颜色
        style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
        style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
        style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());

        // 3. 背景色（默认白色，可不设置）
        style.setFillPatternType(FillPatternType.SOLID_FOREGROUND);
        style.setFillForegroundColor(IndexedColors.WHITE.getIndex());

        // 4. 字体样式
        WriteFont font = new WriteFont();
        font.setFontName("宋体");                       // 字体
        font.setFontHeightInPoints((short) 11);        // 字号
        font.setColor(IndexedColors.BLACK.getIndex()); // 字体颜色
        style.setWriteFont(font);

        // 5. 自动换行（根据需求）
        style.setWrapped(true);

        return style;
    }
    // 自定义表头样式
    private WriteCellStyle getHeaderStyle() {
        WriteCellStyle style = new WriteCellStyle();
        style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
        style.setHorizontalAlignment(HorizontalAlignment.CENTER);
        // 其他样式设置...
        return style;
    }
    // 根据前端传入的sortField转换为实体字段
    private SFunction<bills, ?> getSortField(String sortField) {
        switch (sortField) {
            case "billId": return bills::getBillId;
            case "accountId": return bills::getAccountId;
            case "amount": return bills::getAmount;
            case "dueDate": return bills::getDueDate;
//            case "paymentDate": return bills::getPaymentDate;
            default: return bills::getBillId;
        }
    }
}
